package database

import (
	"abdis/interface/database"
	"abdis/lib/utils"
)

func readFirstKey(args [][]byte) ([]string, []string) {
	key := string(args[0])
	return nil, []string{key}
}

func writeFirstKey(args [][]byte) ([]string, []string) {
	key := string(args[0])
	return []string{key}, nil
}

func readAllKeys(args [][]byte) ([]string, []string) {
	return nil, utils.BytesToStrings(args)
}

func writeAllKeys(args [][]byte) ([]string, []string) {
	return utils.BytesToStrings(args), nil
}

func noPrepare(args [][]byte) ([]string, []string) {
	return nil, nil
}

func rollbackFirstKey(db *DB, args [][]byte) []database.CmdLine {
	key := string(args[0])
	return rollbackGivenKeys(db, key)
}

func rollbackGivenKeys(db *DB, keys ...string) []database.CmdLine {
	var undoCmdLines [][][]byte
	for _, key := range keys {
		_, ok := db.GetEntity(key)
		if !ok {
			// 原本没有这个 key, 在添加后回滚就删除
			undoCmdLines = append(undoCmdLines,
				utils.ToCmdLine("DEL", key))
		} else {
			undoCmdLines = append(undoCmdLines,
				utils.ToCmdLine("DEL", key), // 先清除再设置
				toTTLCmd(db, key).Args)      // 去查出来应该多久过期再设置
		}
	}
	return undoCmdLines
}

func rollbackHashFields(db *DB, key string, fields ...string) []database.CmdLine {
	undoCmdLines := make([][][]byte, 0)
	dict, errReply := db.getAsDict(key)
	if errReply != nil {
		return nil
	}
	if dict == nil {
		undoCmdLines = append(undoCmdLines, utils.ToCmdLine("DEL", key))
		return undoCmdLines
	}

	for _, field := range fields {
		entity, ok := dict.Get(field)
		if !ok {
			undoCmdLines = append(undoCmdLines, utils.ToCmdLine("HDEL", key, field))
		} else {
			val, _ := entity.([]byte)
			undoCmdLines = append(undoCmdLines,
				utils.ToCmdLine("HSET", key, field, string(val)))
		}
	}
	return undoCmdLines
}

func rollbackSetMembers(db *DB, key string, members ...string) []database.CmdLine {
	cmds := make([]database.CmdLine, 0)
	set, errReply := db.getAsSet(key)
	if errReply != nil {
		return nil
	}
	if set == nil {
		cmds = append(cmds, utils.ToCmdLine("DEL", key))
		return cmds
	}

	for _, member := range members {
		ok := set.Has(member)
		if !ok {
			cmds = append(cmds, utils.ToCmdLine("SREM", key, member))
		} else {
			cmds = append(cmds, utils.ToCmdLine("SADD", key, member))
		}
	}
	return cmds
}
